#include "workCmd.h"

static int recvn(int sockfd, void *buf, int length);

int workCmd(int netFd)
{
    client_t *client = (client_t*)calloc(1,sizeof(client_t));
    client->fd = netFd;

    int nameLength = 0;
    recvn(netFd,&nameLength,sizeof(int));
    recvn(netFd,client->userName,nameLength);

    getcwd(client->pwd,sizeof(client->pwd));
    //获取当前路径并发送
    train_t train;
    train.length = strlen(client->pwd);
    memcpy(train.data,client->pwd,train.length);
    send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netFd,train.data,train.length,MSG_NOSIGNAL);
    printf("%s is connet ,pwd is %s fd = %d.\n",
           client->userName,client->pwd,client->fd);

    while(1){
        printf("%s$ \n",client->pwd);
        //接受命令
        char cmd[1024] = {0};
        int cmdLength = 0;
        recvn(netFd,&cmdLength,sizeof(int));
        recvn(netFd,cmd,cmdLength);
        printf("cmd = %s,cmdLength = %d\n",cmd,cmdLength);
        strcpy(client->cmd,cmd);

        //分析命令
        if(strncmp("cd",cmd,2)==0){
            doCd(client);
        }
        else if(strncmp("ls",cmd,2)==0){
            doLs(client);
        }
        else if(strncmp("ll",cmd,2)==0){
            doLl(client);
        }
        else if(strncmp("tree",cmd,4)==0){
            doTree(client);
        }
        else if(strncmp("mkdir",cmd,5)==0){
            doMkdir(client);
        }
        else if(strncmp("rm",cmd,2)==0){
            doRm(client);
        }
        else if(strncmp("get",cmd,3)==0){
            doGet(client);
        }
        else if(strncmp("put",cmd,3)==0){
            doPut(client);
        }
        else if(strncmp("quit",cmd,4)== 0 && cmdLength == 0){
            printf("%s has finished.\n",client->userName);
            free(client);
            break;
        }
    }
    return 0;
}

static int recvn(int sockfd, void *buf, int length){
    int total = 0;
    char *p = (char *)buf;
    while(total < length){
        ssize_t sret = recv(sockfd,p+total,length-total,0);
        total += sret;
    }
    return total;
}

//recvn封装版本，强制recv完，进度条
//小文件秒传，大文件慢慢传
int recvFile(int netfd){
    train_t train;
    char filename[4096] = {0};
    recvn(netfd,&train.length,sizeof(train.length));//收火车头
    recvn(netfd,train.data,train.length);//收车厢
    memcpy(filename,train.data,train.length);
    printf("%s\n",filename);

    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(fd,-1,"open");

    off_t filesize = 0;
    recvn(netfd,&train.length,sizeof(train.length));
    recvn(netfd,train.data,train.length);
    memcpy(&filesize,train.data,train.length);

    printf("Filesize = %ld\n",filesize);
    if(filesize < 4096){
        printf("Tiny file.\n");
        ftruncate(fd,filesize);
        char *p = (char *)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        recvn(netfd,p,filesize);
        munmap(p,filesize);
    }
    else{
        printf("Hurge file~\n");
        off_t currsize = 0;
        while(1){
            recvn(netfd,&train.length,sizeof(train.length));//收火车头
            if(train.length == 0){
                break;
            }
            currsize += train.length;
            printf("%5.2lf%%\r",100.0*currsize/filesize);
            fflush(stdout);

            sleep(1);
            recvn(netfd,train.data,train.length);//收车厢
            write(fd,train.data,train.length);
        }
    }
    printf("100.00%%\n");
    close(fd);
    return 0;
}

int sendFile(int netFd,char *file){
    train_t train;
    train.length = strlen(file);
    memcpy(train.data,file,train.length);
    printf("%d ,%s\n",train.length,train.data);
    send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netFd,train.data,train.length,MSG_NOSIGNAL);

    int fd = open(file,O_RDWR);
    struct stat statbuf;
    fstat(fd,&statbuf);
    off_t filesize = statbuf.st_size;
    train.length = sizeof(filesize);
    memcpy(train.data,&filesize,train.length);
    send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netFd,train.data,train.length,MSG_NOSIGNAL);

    printf("Filesize = %ld\n",filesize);
    //小文件秒传，大文件小火车传
    if(filesize < 4096){
        printf("Tiny file.\n");
        char *p = (char *)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        send(netFd,p,filesize,MSG_NOSIGNAL);
        munmap(p,filesize);
    }
    else{
        printf("Hurge file~\n");
        while(1){
            bzero(train.data,sizeof(train.data));
            ssize_t ret = read(fd,train.data,sizeof(train.data));
            train.length = ret;
            send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
            send(netFd,train.data,train.length,MSG_NOSIGNAL);
            if(ret == 0){
                break;
            }
        }
    }
    close(fd);
    return 0;
}

int doCd(client_t *pclient){
    //接收目录名
    char pwd[1024] = {0};
    int pwdLength = 0;
    recvn(pclient->fd,&pwdLength,sizeof(int));
    recvn(pclient->fd,pwd,pwdLength);
    printf("cd :%s\n",pwd);
    //拼接目录
    /* int ret = chdir(pclient->pwd); */
    char realpwd[1024] = {0};
    char temp[4096] = {0};
    getcwd(realpwd,sizeof(realpwd));
    printf("now: %s\n",realpwd);
    if(strcmp(pwd,"~")== 0){
        sprintf(temp,"%s/%s",realpwd,pwd);
        /* snprintf(realpwd,sizeof(realpwd),"%s/%s",getenv("HOME"),pclient->userName); */
    }else if(pwd[0] == '~'){
        sprintf(temp,"%s/%s",realpwd,pwd +1);
        /* snprintf(realpwd,sizeof(realpwd),"%s/%s",getenv("HOME"),pwd + 1); */
    }else if(pwd[0] != '/'){
        sprintf(temp,"%s/%s",realpwd,pwd);
        /* snprintf(realpwd,sizeof(realpwd),"%s/%s",pclient->pwd,pwd); */
    }else{
        sprintf(temp,"%s/%s",realpwd,pwd);
        /* strcpy(realpwd,pwd); */
    }

    //验证路径
    train_t train;
    struct stat st;
    if(stat(temp,&st) == -1 || !S_ISDIR(st.st_mode)){
        train.length = 0;
        strcpy(train.data,"error");
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
        return 0;
    }

    //更新路径
    strncpy(pclient->pwd,temp,sizeof(pclient->pwd)-1);

    bzero(&train,sizeof(train));
    strcpy(train.data,pclient->pwd);
    /* printf("%s\n",train.data); */
    send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    return 0;
}
int doLs(client_t *pclient){
    DIR *dir = opendir(pclient->pwd);
    ERROR_CHECK(dir,NULL,"opendir");

    struct dirent *dirent_p;
    while((dirent_p = readdir(dir))!= NULL){
        printf("%s\t",dirent_p->d_name);
    }
    printf("\n");
    closedir(dir);
    return 0;
}
int doLl(client_t *pclient){
    return 0;
}
int doPwd(client_t *pclient){
    return 0;
}
int doRm(client_t *pclient){
    return 0;
}
int doMkdir(client_t *pclient){
    return 0;
}
int doTree(client_t *pclient){
    return 0;
}
int doGet(client_t *pclient){
    return 0;
}
int doPut(client_t *pclient){
    return 0;
}


